package org.qpcr.community.auth.service;

import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.hswebframework.ezorm.rdb.mapping.ReactiveQuery;
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
import org.hswebframework.web.crud.service.GenericReactiveTreeSupportCrudService;
import org.hswebframework.web.exception.BusinessException;
import org.hswebframework.web.id.IDGenerator;
import org.hswebframework.web.system.authorization.api.entity.DimensionUserEntity;
import org.hswebframework.web.system.authorization.defaults.service.DefaultDimensionUserService;
import org.qpcr.community.auth.dimension.OrgDimensionType;
import org.qpcr.community.auth.entity.*;
import org.qpcr.community.auth.utils.DimensionUserBindUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.print.attribute.standard.MediaSize;
import java.util.*;

@Service
@AllArgsConstructor
public class OrganizationService extends GenericReactiveTreeSupportCrudService<OrganizationEntity, String> {

    private DefaultDimensionUserService dimensionUserService;
//    private UserDetailService userDetailService;

    @Override
    public IDGenerator<String> getIDGenerator() {
        return IDGenerator.UUID;
    }

    @Override
    public void setChildren(OrganizationEntity entity, List<OrganizationEntity> children) {
        entity.setChildren(children);
    }


//    @Transactional
//    public void add(OrganizationEntity entity) {
//        SaveUserRequest saveUserRequest=new SaveUserRequest();
//        UserDetail user=new UserDetail();
//        user.setPassword("Hgy1111");
//        user.setUsername("testadmn");
//        user.setOrgId("46a8d298-d671-4bc0-814a-6df4bc8fb16b");
//        List<OrganizationInfo> orgList= new ArrayList<OrganizationInfo>();
//        OrganizationInfo organizationInfo=new OrganizationInfo();
//        organizationInfo.setId("46a8d298-d671-4bc0-814a-6df4bc8fb16b");
//        orgList.add(organizationInfo);
//        user.setOrgList(orgList);
//        List<RoleInfo> roleList=new ArrayList<>();
//        RoleInfo roleInfo=new RoleInfo();
//        roleInfo.setId("1800447056730923008");
//        roleList.add(roleInfo);
//        user.setRoleList(roleList);
//        user.setType(UserEntityTypes.getType("CUSTOMADMIN"));
//        user.setUnitId("aaaa");
//        saveUserRequest.setUser(user);
//
//         this.save(entity).then(userDetailService.saveUser(saveUserRequest));
//
//    }


    @Transactional
    public Mono<Integer> bindUser(String orgId, List<String> userIdList) {
        Flux<String> userIdStream = Flux.fromIterable(userIdList);

        return this
            .findById(orgId)
            .flatMap(org -> userIdStream
                .map(userId -> {
                    DimensionUserEntity userEntity = new DimensionUserEntity();
                    userEntity.setUserId(userId);
                    userEntity.setUserName(userId);
                    userEntity.setDimensionId(orgId);
                    userEntity.setDimensionTypeId(OrgDimensionType.org.getId());
                    userEntity.setDimensionName(org.getName());
                    return userEntity;
                })
                .as(dimensionUserService::save))
            .map(SaveResult::getTotal);

    }

    @Transactional
    public Mono<Integer> unbindUser(String orgId, List<String> userIdList) {
        Flux<String> userIdStream = Flux.fromIterable(userIdList);

        return userIdStream
            .collectList()
            .filter(CollectionUtils::isNotEmpty)
            .flatMap(newUserIdList -> dimensionUserService
                .createDelete()
                .where(DimensionUserEntity::getDimensionTypeId, OrgDimensionType.org.getId())
                .in(DimensionUserEntity::getUserId, newUserIdList)
                .and(DimensionUserEntity::getDimensionId, orgId)
                .execute())
            ;
    }


    /**
     * 绑定用户到机构(部门)
     *
     * @param userIdList    用户ID
     * @param orgIdList     机构Id
     * @param removeOldBind 是否删除旧的绑定信息
     * @return void
     */
    @Transactional
    public Mono<Void> bindUser(Collection<String> userIdList,
                               Collection<String> orgIdList,
                               boolean removeOldBind) {
        if (CollectionUtils.isEmpty(userIdList)) {
            return Mono.empty();
        }
        return DimensionUserBindUtils.bindUser(dimensionUserService, userIdList, OrgDimensionType.org.getId(), orgIdList, removeOldBind);
    }


    @Autowired
    private ReactiveRepository<OrganizationEntity, String> repository;

    public Mono<OrganizationEntity> findByname(String name) {
        return Mono.justOrEmpty(name).flatMap((_code) -> {
            return ((ReactiveQuery)this.repository.createQuery().where(OrganizationEntity::getName, _code)).fetchOne();
        });
    }
    public Mono<OrganizationEntity> findByIdName(String name,String id) {
        return Mono.justOrEmpty(name).flatMap((_code) -> {
            return ((ReactiveQuery)this.repository.createQuery().where(OrganizationEntity::getName, _code).and(OrganizationEntity::getLevel,1).not(OrganizationEntity::getId, id)).fetchOne();
        });
    }

    public Mono<OrganizationEntity> findByPhone(String phone) {
        return Mono.justOrEmpty(phone).flatMap((_code) -> {
            return ((ReactiveQuery)this.repository.createQuery().where(OrganizationEntity::getContactPhone, _code)).fetchOne();
        });
    }
    public Mono<OrganizationEntity> findByPhone(String phone,String id) {
        return Mono.justOrEmpty(phone).flatMap((_code) -> {
            return ((ReactiveQuery)this.repository.createQuery().where(OrganizationEntity::getContactPhone, _code).and(OrganizationEntity::getLevel,1).not(OrganizationEntity::getId, id)).fetchOne();
        });
    }

    public Mono<OrganizationEntity> findByKey(String key) {
        return Mono.justOrEmpty(key)
                   .flatMap(_code -> {
                       return ((ReactiveQuery)this.repository.createQuery().where(OrganizationEntity::getKey, _code))
                           .fetchOne();
                   })
                   .switchIfEmpty( Mono.error(new BusinessException("找不到该key对应的组织信息", -200)));  // 如果没有数据，抛出异常
    }

    public Mono<OrganizationEntity> queryApiKeyByOrgId(String id) {
        return this.findById(id)
                   .flatMap(org -> {
                       // 如果 org 的 key 为 null，则生成一个新的 UUID 并更新对象
                       if (org.getKey() == null) {
                           String uuid = UUID.randomUUID().toString();
                           org.setKey(uuid);
                           // 使用 flatMap 返回更新操作的结果，确保在更新后继续返回 org
                           return this.updateById(org.getId(), org)
                                      .thenReturn(org);  // update 操作完成后返回 org
                       } else {
                           return Mono.just(org);  // 如果 org 已经有 key，直接返回 org
                       }
                   });
    }



}
